import sys
import numpy as np
import pandas as pd
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
from pyqtgraph.exporters import ImageExporter
from src.sharedSrc import getSetting


class TrendChart(QWidget):
    def __init__(self):
        super().__init__()
        # Initialize layout and plot area
        self.layout = QVBoxLayout(self)
        self.plotlayout = pg.GraphicsLayoutWidget()
        self.plotlayout.setBackground('white')  # Set the entire plot area background to white
        self.layout.addWidget(self.plotlayout)
        self.setLayout(self.layout)
        self.view_list = []
        self.settings = getSetting()
        # Initialize settings
        self.inin_Data()
        self.position = {0: "xCoord", 1: "yCoord"}

    def inin_Data(self):
        self.showMean_trend = self.settings.showMean_trend
        self.showMed_trend = self.settings.showMedian_trend
        self.showLL_trend = self.settings.showLL_trend
        self.showHL_trend = self.settings.showHL_trend
        self.showLSpec_trend = self.settings.showLSpec_trend
        self.showHSpec_trend = self.settings.showHSpec_trend
        self.fileSymbol = {0: self.settings.xCoord_symbol, 1: self.settings.yCoord_symbol}
        self.siteColor = {0: self.settings.xCoord_color, 1: self.settings.yCoord_color}
        self.meanPen = pg.mkPen({"color": self.settings.trend_dict['mean'], "width": self.settings.trend_width['mean']})
        self.medianPen = pg.mkPen(
            {"color": self.settings.trend_dict['median'], "width": self.settings.trend_width['median']})
        self.lolimitPen = pg.mkPen(
            {"color": self.settings.trend_dict['llimit'], "width": self.settings.trend_width['llimit']})
        self.hilimitPen = pg.mkPen(
            {"color": self.settings.trend_dict['hlimit'], "width": self.settings.trend_width['hlimit']})
        self.lospecPen = pg.mkPen(
            {"color": self.settings.trend_dict['lspec'], "width": self.settings.trend_width['lspec']})
        self.hispecPen = pg.mkPen(
            {"color": self.settings.trend_dict['hspec'], "width": self.settings.trend_width['hspec']})

    def setTrendData(self, trendData: dict, file_name: str = '') -> bool:
        testInfo = trendData["TestInfo"]
        testData = trendData["Data"]

        y_min_list = []
        y_max_list = []
        for fid in testData.keys():
            i_file = testInfo[fid]
            if len(i_file) == 0:
                return False
            y_min_list.append(i_file["LLimit"])
            y_max_list.append(i_file["HLimit"])
            y_min_list.append(i_file["LSpec"])
            y_max_list.append(i_file["HSpec"])

        y_min = np.nanmin(y_min_list)
        y_max = np.nanmax(y_max_list)
        oh = 0.15 * (y_max - y_min)
        y_min -= oh
        y_max += oh

        if y_min == y_max:
            y_min -= 1
            y_max += 1

        for fid in sorted(testInfo.keys()):


            view = pg.ViewBox()

            pitem = pg.PlotItem(viewBox=view)
            pitem.addLegend((0, 1), labelTextSize="12pt")

            sitesData = testData[fid]
            infoDict = testInfo[fid]
            if len(sitesData) == 0 or len(infoDict) == 0:
                continue

            x_min_list = []
            x_max_list = []

            for site, data_per_site in sitesData.items():
                x = data_per_site["dutList"]
                y = data_per_site["dataList"]
                if len(x) == 0 or len(y) == 0:
                    continue

                x_min_list.append(np.nanmin(x))
                x_max_list.append(np.nanmax(x))

                fsymbol = self.fileSymbol[site]
                siteColor = self.siteColor[site]
                # site_info = "All Site" if site == -1 else f"Site {site}"
                testName, signal = data_per_site["TestName"], data_per_site["Signal"]
                coord = self.position[site]
                site_info = f"Test Name: {testName} Signal: {signal} Coord: {coord}"
                site_info2 = f"Test Name: {testName} \nSignal: {signal} \nCoord: {coord}\n"

                pdi = pg.PlotDataItem(x=x, y=y, pen=None, symbol=fsymbol, symbolPen="k", symbolSize=10,
                                      symbolBrush=siteColor, name=f"{site_info}")
                pdi.scatter.opts.update(hoverable=True,
                                        tip=f"{site_info2}\nDUTIndex: {{x:.0f}}\nValue: {{y:.3g}}".format,
                                        hoverSymbol="+", hoverSize=12, hoverPen=pg.mkPen("#ff0000", width=1))
                pitem.addItem(pdi)

                mean = data_per_site["Mean"]
                if self.showMean_trend and ~np.isnan(mean):
                    pitem.addLine(y=mean, pen=self.meanPen, name=f"Mean_site{site}", label="x̅ = {value:0.6f}",
                                  labelOpts={"position": 0.9, "color": self.meanPen.color(), "movable": True})

                median = data_per_site["Median"]
                if self.showMed_trend and ~np.isnan(median):
                    pitem.addLine(y=median, pen=self.medianPen, name=f"Median_site{site}", label="x̃ = {value:0.6f}",
                                  labelOpts={"position": 0.7, "color": self.medianPen.color(), "movable": True})

            for (key, name, pen, enabled) in [("LLimit", "Low Limit", self.lolimitPen, self.showLL_trend),
                                              ("HLimit", "High Limit", self.hilimitPen, self.showHL_trend),
                                              ("LSpec", "Low Spec", self.lospecPen, self.showLSpec_trend),
                                              ("HSpec", "High Spec", self.hispecPen, self.showHSpec_trend)]:

                lim = infoDict[key]
                pos = 0.8 if key.endswith("Spec") else 0.2
                anchors = [(0.5, 0), (0.5, 0)] if key.startswith("L") else [(0.5, 1), (0.5, 1)]
                if enabled and ~np.isnan(lim):
                    pitem.addLine(y=lim, pen=pen, name=name, label=f"{name} = {{value:0.6f}}",
                                  labelOpts={"position": pos, "color": pen.color(), "movable": True,
                                             "anchors": anchors})

            unit = infoDict["Unit"]
            pitem.getAxis("left").setLabel(f"Test Value ({unit})" if unit else "Test Value")
            pitem.getAxis("bottom").setLabel("DUTIndex")

            pitem.setClipToView(True)

            x_min = min(x_min_list)
            x_max = max(x_max_list)
            oh = 0.02 * (x_max - x_min)
            x_min -= oh
            x_max += oh

            view.setLimits(xMin=x_min, xMax=x_max, yMin=y_min, yMax=y_max)

            self.view_list.append(view)
            self.plotlayout.addItem(pitem)

            if file_name != '':
                self.save_plot(file_name)

        return True

    def save_plot(self, filename: str) -> None:
        exporter = ImageExporter(self.plotlayout.scene())
        exporter.export(filename)


def trend_data(df, testName: str, signal: str) -> dict:
    trendData = {
        "TestInfo": {1: {

        }},
        "Data": {1: {}}
    }

    # Filter DataFrame once instead of multiple times
    data = df[(df['TestName'] == testName) & (df['Signal'] == signal)]

    # Initialize relevant lists and conversion factors
    measure_list = ['LowLimit', 'HighLimit']
    units = ["mV", "mA", "uA", "nA", "A", "uV", "nV", "V"]
    unit_conversion = [1, 1, 10e-3, 10e-6, 1e3, 10e-3, 10e-6, 1e3]

    voltages = [data[measure].values[0] for measure in measure_list]
    parsed_voltages = []
    unit = None

    for v in voltages:
        for u in units:
            if u in v:
                parsed_value = float(v.replace(u, ''))
                parsed_voltages.append(parsed_value * unit_conversion[units.index(u)])
                unit = u
                break
        if unit is None:
            return trendData

    measure_columns = [col for col in df.columns if 'Measure' in col]

    XCoordDF = df[df['Force'] == 'XCoord']
    YCoordDF = df[df['Force'] == 'YCoord']

    dataList = []
    XCoord = []
    YCoord = []

    for measure in measure_columns:
        xyData = data[measure].values[0]
        if pd.isna(xyData):
            continue

        x_values = int(XCoordDF[measure].values[0])
        y_values = int(YCoordDF[measure].values[0])

        for u in units:
            if u in xyData:
                rmUnitData = float(xyData.replace(u, '')) * unit_conversion[units.index(u)]
                dataList.append(rmUnitData)
                XCoord.append(x_values)
                YCoord.append(y_values)
                break

    mean = np.mean(dataList)
    median = np.median(dataList)
    lSpec = np.min(dataList)
    hSpec = np.max(dataList)

    xData = {
        "dutList": XCoord,
        "dataList": dataList,
        "Mean": mean,
        "Median": median,
        "TestName": testName,
        "Signal": signal
    }
    yData = {
        "dutList": YCoord,
        "dataList": dataList,
        "Mean": mean,
        "Median": median,
        "TestName": testName,
        "Signal": signal
    }

    trendData["TestInfo"][1] = {
        "LLimit": parsed_voltages[0],
        "HLimit": parsed_voltages[1],
        "Unit": "mV/mA",
        "LSpec": lSpec,
        "HSpec": hSpec
    }
    trendData["Data"][1][0] = xData
    trendData["Data"][1][1] = yData

    return trendData


if __name__ == "__main__":
    app = QApplication(sys.argv)

    trend_chart = TrendChart()
    df = pd.read_csv(r"D:\dataset\new\22.csv", low_memory=False)
    mock_data = trend_data(df, "OS", "iwen")
    t = trend_chart.setTrendData(mock_data)
    print(
        t
    )
    trend_chart.show()

    sys.exit(app.exec_())
